//modified by Tim Anderson for Silverlight compatibility
//quick hack for proof of concept, not production quality!
//see http://www.itwriting.com/blog/1695-proof-of-concept-c-sqlite-running-in-silverlight.html

#define SQLITE_OS_WIN

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

#if SQLITE_SILVERLIGHT
using System.IO.IsolatedStorage;
#else
using System.Runtime.InteropServices;
#endif

using HANDLE = System.IntPtr;
using DWORD = System.UInt64;
using WORD = System.Int32;
using i64 = System.Int64;
using u8 = System.Byte;
using u32 = System.UInt32;

using sqlite3_int64 = System.Int64;

#if GWNDESKTOP
using Community.CsharpSqlite.Desktop;
#endif

namespace Community.CsharpSqlite
{
    public partial class Sqlite3
    {
        public static IsolatedStorageFile _isolatedStorageFile;
        private static IsolatedStorageFile _store;
        /// <summary>
        /// Single entry point for all process to obtain IsolatedStorageFile
        /// </summary>
        /// <returns></returns>
        public static IsolatedStorageFile GetUserStoreForApplication()
        {
#if UNIT_TEST 
            // GetUserStoreForApplication generates the error
            // "Unable to determine application identity of the caller"
            // so we'll use external assembly call, which uses GetStore(),
            // during Unit Test.   The external file will serve as a 
            // single entry point for other projects that require a reference
            var appVersion = Activator.CreateInstance<ApplicationVersion>();
            _isolatedStorageFile = appVersion.GetIsolatedStorageFile();
            return _isolatedStorageFile;

            //// If we made it this far and _isolatedStorageFile is null
            //// then get store for assembly
            //_isolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly();
            //return _isolatedStorageFile;
#else
            _store = IsolatedStorageFile.GetUserStoreForApplication();
            return _store;
#endif
        }

        /*
        ** 2004 May 22
        **
        ** The author disclaims copyright to this source code.  In place of
        ** a legal notice, here is a blessing:
        **
        **    May you do good and not evil.
        **    May you find forgiveness for yourself and forgive others.
        **    May you share freely, never taking more than you give.
        **
        ******************************************************************************
        **
        ** This file contains code that is specific to windows.
        **
        ** $Id: os_win.c,v 1.156 2009/04/23 19:08:33 shane Exp $
        **
        *************************************************************************
        **  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
        **  C#-SQLite is an independent reimplementation of the SQLite software library 
        **
        **  $Header$
        *************************************************************************
        */
        //#include "sqliteInt.h"
#if SQLITE_OS_WIN               // * This file is used for windows only */


        /*
** A Note About Memory Allocation:
**
** This driver uses malloc()/free() directly rather than going through
** the SQLite-wrappers sqlite3Malloc()/sqlite3DbFree(db,ref  ).  Those wrappers
** are designed for use on embedded systems where memory is scarce and
** malloc failures happen frequently.  Win32 does not typically run on
** embedded systems, and when it does the developers normally have bigger
** problems to worry about than running out of memory.  So there is not
** a compelling need to use the wrappers.
**
** But there is a good reason to not use the wrappers.  If we use the
** wrappers then we will get simulated malloc() failures within this
** driver.  And that causes all kinds of problems for our tests.  We
** could enhance SQLite to deal with simulated malloc failures within
** the OS driver, but the code to deal with those failure would not
** be exercised on Linux (which does not need to malloc() in the driver)
** and so we would have difficulty writing coverage tests for that
** code.  Better to leave the code out, we think.
**
** The point of this discussion is as follows:  When creating a new
** OS layer for an embedded system, if you use this file as an example,
** avoid the use of malloc()/free().  Those routines work ok on windows
** desktops but not so well in embedded systems.
*/

        //#include <winbase.h>

#if __CYGWIN__
/# include <sys/cygwin.h>
#endif

        /*
** Macros used to determine whether or not to use threads.
*/
#if THREADSAFE
/# define SQLITE_W32_THREADS 1
#endif

        /*
** Include code that is common to all os_*.c files
*/
        //#include "os_common.h"

        /*
        ** Some microsoft compilers lack this definition.
        */
#if !INVALID_FILE_ATTRIBUTES
        //# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 
        const int INVALID_FILE_ATTRIBUTES = -1;
#endif

        /*
** Determine if we are dealing with WindowsCE - which has a much
** reduced API.
*/
#if SQLITE_OS_WINCE
/# define AreFileApisANSI() 1
/# define GetDiskFreeSpaceW() 0
#endif

        /*
** WinCE lacks native support for file locking so we have to fake it
** with some code of our own.
*/
#if SQLITE_OS_WINCE
typedef struct winceLock {
int nReaders;       /* Number of reader locks obtained */
BOOL bPending;      /* Indicates a pending lock has been obtained */
BOOL bReserved;     /* Indicates a reserved lock has been obtained */
BOOL bExclusive;    /* Indicates an exclusive lock has been obtained */
} winceLock;
#endif

        /*
** The winFile structure is a subclass of sqlite3_file* specific to the win32
** portability layer.
*/
        //typedef struct sqlite3_file sqlite3_file;
        public partial class sqlite3_file
        {
#if SQLITE_SILVERLIGHT
            public IsolatedStorageFileStream fs;
#else
        public FileStream fs;          /* Filestream access to this file*/
#endif
            // public HANDLE h;            /* Handle for accessing the file */
            public int locktype;           /* Type of lock currently held on this file */
            public int sharedLockByte;     /* Randomly chosen byte used as a shared lock */
            public DWORD lastErrno;        /* The Windows errno from the last I/O error */
            public DWORD sectorSize;       /* Sector size of the device file is on */
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
HANDLE hMutex;          /* Mutex used to control access to shared lock */  
HANDLE hShared;         /* Shared memory segment used for locking */
winceLock local;        /* Locks obtained by this instance of sqlite3_file */
winceLock *shared;      /* Global shared lock memory for the file  */
#endif
        };

        /*
        ** Forward prototypes.
        */
        //static int getSectorSize(
        //    sqlite3_vfs *pVfs,
        //    const char *zRelative     /* UTF-8 file name */
        //);

        /*
        ** The following variable is (normally) set once and never changes
        ** thereafter.  It records whether the operating system is Win95
        ** or WinNT.
        **
        ** 0:   Operating system unknown.
        ** 1:   Operating system is Win95.
        ** 2:   Operating system is WinNT.
        **
        ** In order to facilitate testing on a WinNT system, the test fixture
        ** can manually set this value to 1 to emulate Win98 behavior.
        */
#if SQLITE_TEST
    int sqlite3_os_type = 0;
#else
        static int sqlite3_os_type = 0;
#endif

        /*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
** or WinCE.  Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation:  Win95, Win98, and WinME lack
** the LockFileEx() API.  But we can still statically link against that
** API as long as we don't call it when running Win95/98/ME.  A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
*/

#if SQLITE_OS_WINCE
    /# define isNT()  (1)
#else
        static bool isNT()
        {

#if UNIT_TEST
            // We want to emulate the WP7 environment as closely as
            // possible so we need to return true since this is the
            // result returned by the phone (reports WinCE)
            return true;
#endif
            #region COMMENTED OUT Code
            //if (sqlite3_os_type == 0)
            //{
            //  OSVERSIONINFO sInfo;
            //  sInfo.dwOSVersionInfoSize = sInfo.Length;
            //  GetVersionEx(&sInfo);
            //  sqlite3_os_type = sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ? 2 : 1;
            //}
            //return sqlite3_os_type == 2;
            #endregion
            return Environment.OSVersion.Platform >= PlatformID.Win32NT;
        }
#endif // * SQLITE_OS_WINCE */


#if SQLITE_SILVERLIGHT
        static bool ExistsFile(string sFilename)
        {
            using (var store = GetUserStoreForApplication())
            {
                return (store.FileExists(sFilename));
            }
        }

        static void DeleteFile(string sFilename)
        {
            using (var store = GetUserStoreForApplication())
            {
                store.DeleteFile(sFilename);
            }
        }

#endif

        /*
** Convert a UTF-8 string to microsoft unicode (UTF-16?). 
**
** Space to hold the returned string is obtained from malloc.
*/
        //static WCHAR *utf8ToUnicode(string zFilename){
        //  int nChar;
        //  WCHAR *zWideFilename;

        //  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
        //  zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) );
        //  if( zWideFilename==0 ){
        //    return 0;
        //  }
        //  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
        //  if( nChar==0 ){
        //    free(zWideFilename);
        //    zWideFileName = "";
        //  }
        //  return zWideFilename;
        //}

        /*
        ** Convert microsoft unicode to UTF-8.  Space to hold the returned string is
        ** obtained from malloc().
        */
        //static char *unicodeToUtf8(const WCHAR *zWideFilename){
        //  int nByte;
        //  char *zFilename;

        //  nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
        //  zFilename = malloc( nByte );
        //  if( zFilename==0 ){
        //    return 0;
        //  }
        //  nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
        //                              0, 0);
        //  if( nByte == 0 ){
        //    free(zFilename);
        //    zFileName = "";
        //  }
        //  return zFilename;
        //}

        /*
        ** Convert an ansi string to microsoft unicode, based on the
        ** current codepage settings for file apis.
        ** 
        ** Space to hold the returned string is obtained
        ** from malloc.
        */
        //static WCHAR *mbcsToUnicode(string zFilename){
        //  int nByte;
        //  WCHAR *zMbcsFilename;
        //  int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;

        //  nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*WCHAR.Length;
        //  zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) );
        //  if( zMbcsFilename==0 ){
        //    return 0;
        //  }
        //  nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
        //  if( nByte==0 ){
        //    free(zMbcsFilename);
        //    zMbcsFileName = "";
        //  }
        //  return zMbcsFilename;
        //}

        /*
        ** Convert microsoft unicode to multibyte character string, based on the
        ** user's Ansi codepage.
        **
        ** Space to hold the returned string is obtained from
        ** malloc().
        */
        //static char *unicodeToMbcs(const WCHAR *zWideFilename){
        //  int nByte;
        //  char *zFilename;
        //  int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;

        //  nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
        //  zFilename = malloc( nByte );
        //  if( zFilename==0 ){
        //    return 0;
        //  }
        //  nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
        //                              0, 0);
        //  if( nByte == 0 ){
        //    free(zFilename);
        //    zFileName = "";
        //  }
        //  return zFilename;
        //}

        /*
        ** Convert multibyte character string to UTF-8.  Space to hold the
        ** returned string is obtained from malloc().
        */
        //static char *sqlite3_win32_mbcs_to_utf8(string zFilename){
        //  char *zFilenameUtf8;
        //  WCHAR *zTmpWide;

        //  zTmpWide = mbcsToUnicode(zFilename);
        //  if( zTmpWide==0 ){
        //    return 0;
        //  }
        //  zFilenameUtf8 = unicodeToUtf8(zTmpWide);
        //  free(zTmpWide);
        //  return zFilenameUtf8;
        //}

        /*
        ** Convert UTF-8 to multibyte character string.  Space to hold the 
        ** returned string is obtained from malloc().
        */
        //static char *utf8ToMbcs(string zFilename){
        //  char *zFilenameMbcs;
        //  WCHAR *zTmpWide;

        //  zTmpWide = utf8ToUnicode(zFilename);
        //  if( zTmpWide==0 ){
        //    return 0;
        //  }
        //  zFilenameMbcs = unicodeToMbcs(zTmpWide);
        //  free(zTmpWide);
        //  return zFilenameMbcs;
        //}

#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
*/
/*
** WindowsCE does not have a localtime() function.  So create a
** substitute.
*/
/#include <time.h>
struct tm *__cdecl localtime(const time_t *t)
{
static struct tm y;
FILETIME uTm, lTm;
SYSTEMTIME pTm;
sqlite3_int64 t64;
t64 = *t;
t64 = (t64 + 11644473600)*10000000;
uTm.dwLowDateTime = t64 & 0xFFFFFFFF;
uTm.dwHighDateTime= t64 >> 32;
FileTimeToLocalFileTime(&uTm,&lTm);
FileTimeToSystemTime(&lTm,&pTm);
y.tm_year = pTm.wYear - 1900;
y.tm_mon = pTm.wMonth - 1;
y.tm_wday = pTm.wDayOfWeek;
y.tm_mday = pTm.wDay;
y.tm_hour = pTm.wHour;
y.tm_min = pTm.wMinute;
y.tm_sec = pTm.wSecond;
return &y;
}

/* This will never be called, but defined to make the code compile */
/#define GetTempPathA(a,b)

/#define LockFile(a,b,c,d,e)       winceLockFile(&a, b, c, d, e)
/#define UnlockFile(a,b,c,d,e)     winceUnlockFile(&a, b, c, d, e)
/#define LockFileEx(a,b,c,d,e,f)   winceLockFileEx(&a, b, c, d, e, f)

/#define HANDLE_TO_WINFILE(a) (sqlite3_file*)&((char*)a)[-offsetof(sqlite3_file,h)]

/*
** Acquire a lock on the handle h
*/
static void winceMutexAcquire(HANDLE h){
DWORD dwErr;
do {
dwErr = WaitForSingleObject(h, INFINITE);
} while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
}
/*
** Release a lock acquired by winceMutexAcquire()
*/
/#define winceMutexRelease(h) ReleaseMutex(h)

/*
** Create the mutex and shared memory used for locking in the file
** descriptor pFile
*/
static BOOL winceCreateLock(string zFilename, sqlite3_file pFile){
WCHAR *zTok;
WCHAR *zName = utf8ToUnicode(zFilename);
BOOL bInit = TRUE;

/* Initialize the local lockdata */
ZeroMemory(pFile.local, pFile.local).Length;

/* Replace the backslashes from the filename and lowercase it
** to derive a mutex name. */
zTok = CharLowerW(zName);
for (;*zTok;zTok++){
if (*zTok == '\\') *zTok = '_';
}

/* Create/open the named mutex */
pFile.hMutex = CreateMutexW(NULL, FALSE, zName);
if (!pFile.hMutex){
pFile->lastErrno = (u32)GetLastError();
free(zName);
return FALSE;
}

/* Acquire the mutex before continuing */
winceMutexAcquire(pFile.hMutex);

/* Since the names of named mutexes, semaphores, file mappings etc are 
** case-sensitive, take advantage of that by uppercasing the mutex name
** and using that as the shared filemapping name.
*/
CharUpperW(zName);
pFile.hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, winceLock.Length,
zName);  

/* Set a flag that indicates we're the first to create the memory so it 
** must be zero-initialized */
if (GetLastError() == ERROR_ALREADY_EXISTS){
bInit = FALSE;
}

free(zName);

/* If we succeeded in making the shared memory handle, map it. */
if (pFile.hShared){
pFile.shared = (winceLock*)MapViewOfFile(pFile.hShared, 
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, winceLock).Length;
/* If mapping failed, close the shared memory handle and erase it */
if (!pFile.shared){
pFile->lastErrno = (u32)GetLastError();
CloseHandle(pFile.hShared);
pFile.hShared = NULL;
}
}

/* If shared memory could not be created, then close the mutex and fail */
if (pFile.hShared == NULL){
winceMutexRelease(pFile.hMutex);
CloseHandle(pFile.hMutex);
pFile.hMutex = NULL;
return FALSE;
}

/* Initialize the shared memory if we're supposed to */
if (bInit) {
ZeroMemory(pFile.shared, winceLock).Length;
}

winceMutexRelease(pFile.hMutex);
return TRUE;
}

/*
** Destroy the part of sqlite3_file that deals with wince locks
*/
static void winceDestroyLock(sqlite3_file pFile){
if (pFile.hMutex){
/* Acquire the mutex */
winceMutexAcquire(pFile.hMutex);

/* The following blocks should probably Debug.Assert in debug mode, but they
are to cleanup in case any locks remained open */
if (pFile.local.nReaders){
pFile.shared.nReaders --;
}
if (pFile.local.bReserved){
pFile.shared.bReserved = FALSE;
}
if (pFile.local.bPending){
pFile.shared.bPending = FALSE;
}
if (pFile.local.bExclusive){
pFile.shared.bExclusive = FALSE;
}

/* De-reference and close our copy of the shared memory handle */
UnmapViewOfFile(pFile.shared);
CloseHandle(pFile.hShared);

/* Done with the mutex */
winceMutexRelease(pFile.hMutex);    
CloseHandle(pFile.hMutex);
pFile.hMutex = NULL;
}
}

/* 
** An implementation of the LockFile() API of windows for wince
*/
static BOOL winceLockFile(
HANDLE phFile,
DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh
){
sqlite3_file pFile = HANDLE_TO_WINFILE(phFile);
BOOL bReturn = FALSE;

if (!pFile.hMutex) return TRUE;
winceMutexAcquire(pFile.hMutex);

/* Wanting an exclusive lock? */
if (dwFileOffsetLow == SHARED_FIRST
&& nNumberOfBytesToLockLow == SHARED_SIZE){
if (pFile.shared.nReaders == 0 && pFile.shared.bExclusive == 0){
pFile.shared.bExclusive = TRUE;
pFile.local.bExclusive = TRUE;
bReturn = TRUE;
}
}

/* Want a read-only lock? */
else if ((dwFileOffsetLow >= SHARED_FIRST &&
dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) &&
nNumberOfBytesToLockLow == 1){
if (pFile.shared.bExclusive == 0){
pFile.local.nReaders ++;
if (pFile.local.nReaders == 1){
pFile.shared.nReaders ++;
}
bReturn = TRUE;
}
}

/* Want a pending lock? */
else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToLockLow == 1){
/* If no pending lock has been acquired, then acquire it */
if (pFile.shared.bPending == 0) {
pFile.shared.bPending = TRUE;
pFile.local.bPending = TRUE;
bReturn = TRUE;
}
}
/* Want a reserved lock? */
else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
if (pFile.shared.bReserved == 0) {
pFile.shared.bReserved = TRUE;
pFile.local.bReserved = TRUE;
bReturn = TRUE;
}
}

winceMutexRelease(pFile.hMutex);
return bReturn;
}

/*
** An implementation of the UnlockFile API of windows for wince
*/
static BOOL winceUnlockFile(
HANDLE phFile,
DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToUnlockLow,
DWORD nNumberOfBytesToUnlockHigh
){
sqlite3_file pFile = HANDLE_TO_WINFILE(phFile);
BOOL bReturn = FALSE;

if (!pFile.hMutex) return TRUE;
winceMutexAcquire(pFile.hMutex);

/* Releasing a reader lock or an exclusive lock */
if (dwFileOffsetLow >= SHARED_FIRST &&
dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE){
/* Did we have an exclusive lock? */
if (pFile.local.bExclusive){
pFile.local.bExclusive = FALSE;
pFile.shared.bExclusive = FALSE;
bReturn = TRUE;
}

/* Did we just have a reader lock? */
else if (pFile.local.nReaders){
pFile.local.nReaders --;
if (pFile.local.nReaders == 0)
{
pFile.shared.nReaders --;
}
bReturn = TRUE;
}
}

/* Releasing a pending lock */
else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
if (pFile.local.bPending){
pFile.local.bPending = FALSE;
pFile.shared.bPending = FALSE;
bReturn = TRUE;
}
}
/* Releasing a reserved lock */
else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
if (pFile.local.bReserved) {
pFile.local.bReserved = FALSE;
pFile.shared.bReserved = FALSE;
bReturn = TRUE;
}
}

winceMutexRelease(pFile.hMutex);
return bReturn;
}

/*
** An implementation of the LockFileEx() API of windows for wince
*/
static BOOL winceLockFileEx(
HANDLE phFile,
DWORD dwFlags,
DWORD dwReserved,
DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh,
LPOVERLAPPED lpOverlapped
){
/* If the caller wants a shared read lock, forward this call
** to winceLockFile */
if (lpOverlapped.Offset == SHARED_FIRST &&
dwFlags == 1 &&
nNumberOfBytesToLockLow == SHARED_SIZE){
return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
}
return FALSE;
}
/*
** End of the special code for wince
*****************************************************************************/
#endif // * SQLITE_OS_WINCE */

        /*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
******************************************************************************/

        /*
        ** Close a file.
        **
        ** It is reported that an attempt to close a handle might sometimes
        ** fail.  This is a very unreasonable result, but windows is notorious
        ** for being unreasonable so I do not doubt that it might happen.  If
        ** the close fails, we pause for 100 milliseconds and try again.  As
        ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
        ** giving up and returning an error.
        */
        public static int MX_CLOSE_ATTEMPT = 3;
        static int winClose(sqlite3_file id)
        {
            bool rc;
            int cnt = 0;
            sqlite3_file pFile = (sqlite3_file)id;

            Debug.Assert(id != null);
#if SQLITE_DEBUG
            //OSTRACE3( "CLOSE %d (%s)\n", pFile.fs.GetHashCode(), pFile.fs.Name );
#endif
            do
            {
                pFile.fs.Close();
                rc = true;
                //  rc = CloseHandle(pFile.h);
                //  if (!rc && ++cnt < MX_CLOSE_ATTEMPT) Thread.Sleep(100); //, 1) );
            } while (!rc && ++cnt < MX_CLOSE_ATTEMPT); //, 1) );
#if SQLITE_OS_WINCE
/#define WINCE_DELETION_ATTEMPTS 3
winceDestroyLock(pFile);
if( pFile.zDeleteOnClose ){
int cnt = 0;
while(
DeleteFileW(pFile.zDeleteOnClose)==0
&& GetFileAttributesW(pFile.zDeleteOnClose)!=0xffffffff 
&& cnt++ < WINCE_DELETION_ATTEMPTS
){
Sleep(100);  /* Wait a little before trying again */
}
free(pFile.zDeleteOnClose);
}
#endif
#if SQLITE_TEST
      OpenCounter( -1 );
#endif
            return rc ? SQLITE_OK : SQLITE_IOERR;
        }

        /*
        ** Some microsoft compilers lack this definition.
        */
#if !INVALID_SET_FILE_POINTER
        const int INVALID_SET_FILE_POINTER = -1;
#endif

        /*
** Read data from a file into a buffer.  Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
        static int winRead(
        sqlite3_file id,           /* File to read from */
        byte[] pBuf,           /* Write content into this buffer */
        int amt,                   /* Number of bytes to read */
        sqlite3_int64 offset       /* Begin reading at this offset */
        )
        {

            //LONG upperBits = (LONG)( ( offset >> 32 ) & 0x7fffffff );
            //LONG lowerBits = (LONG)( offset & 0xffffffff );
            long rc;
            sqlite3_file pFile = id;
            //DWORD error;
            long got;

            Debug.Assert(id != null);
#if SQLITE_TEST
      //SimulateIOError(return SQLITE_IOERR_READ);  TODO --  How to implement this?
#endif
#if SQLITE_DEBUG
            //OSTRACE3( "READ %d lock=%d\n", pFile.fs.GetHashCode(), pFile.locktype );
#endif
            if (!id.fs.CanRead) return SQLITE_IOERR_READ;
            try
            {
                rc = id.fs.Seek(offset, SeekOrigin.Begin); // SetFilePointer(pFile.fs.Name, lowerBits, upperBits, FILE_BEGIN);
            }
            catch (IOException e)      //            if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR )
            {
#if SQLITE_SILVERLIGHT
                pFile.lastErrno = 1;
#else
          pFile.lastErrno = (u32)GetLastError();
#endif
                return SQLITE_FULL;
            }

            try
            {
                got = id.fs.Read(pBuf, 0, amt); // if (!ReadFile(pFile.fs.Name, pBuf, amt, got, 0))
            }
            catch (IOException e)
            {
#if SQLITE_SILVERLIGHT
                pFile.lastErrno = 1;
#else
          pFile.lastErrno = (u32)GetLastError();
#endif

                return SQLITE_IOERR_READ;
            }
            if (got == amt)
            {
                return SQLITE_OK;
            }
            else
            {
                /* Unread parts of the buffer must be zero-filled */
                Array.Clear(pBuf, (int)got, (int)(amt - got)); // memset(&((char*)pBuf)[got], 0, amt - got);
                return SQLITE_IOERR_SHORT_READ;
            }
        }

        /*
        ** Write data from a buffer into a file.  Return SQLITE_OK on success
        ** or some other error code on failure.
        */
        static int winWrite(
        sqlite3_file id,          /* File to write into */
        byte[] pBuf,              /* The bytes to be written */
        int amt,                  /* Number of bytes to write */
        sqlite3_int64 offset      /* Offset into the file to begin writing at */
        )
        {
            //LONG upperBits = (LONG)( ( offset >> 32 ) & 0x7fffffff );
            //LONG lowerBits = (LONG)( offset & 0xffffffff );
            int rc;
            //  sqlite3_file pFile = (sqlite3_file*)id;
            //  DWORD error;
            long wrote = 0;

            Debug.Assert(id != null);
#if SQLITE_TEST
      if ( SimulateIOError() ) return SQLITE_IOERR_WRITE;
      if ( SimulateDiskfullError() ) return SQLITE_FULL;
#endif
#if SQLITE_DEBUG
            //OSTRACE3( "WRITE %d lock=%d\n", id.fs.GetHashCode(), id.locktype );
#endif
            //  rc = SetFilePointer(pFile.fs.Name, lowerBits, upperBits, FILE_BEGIN);
            id.fs.Seek(offset, SeekOrigin.Begin);
            //  if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
            //  pFile.lastErrno = (u32)GetLastError();
            //    return SQLITE_FULL;
            //  }
            Debug.Assert(amt > 0);
            wrote = id.fs.Position;
            try
            {
                Debug.Assert(pBuf.Length >= amt);
                id.fs.Write(pBuf, 0, amt);
                rc = 1;// Success
                wrote = id.fs.Position - wrote;
            }
            catch (IOException e)
            {
                return SQLITE_READONLY;
            }
            //  while(
            //     amt>0
            //     && (rc = WriteFile(pFile.fs.Name, pBuf, amt, wrote, 0))!=0
            //     && wrote>0
            //  ){
            //    amt -= wrote;
            //    pBuf = &((char*)pBuf)[wrote];
            //  }
            if (rc == 0 || amt > (int)wrote)
            {

#if SQLITE_SILVERLIGHT
                id.lastErrno = 1;
#else
          id.lastErrno = (u32)GetLastError();
#endif
                return SQLITE_FULL;
            }
            return SQLITE_OK;
        }

        /*
        ** Truncate an open file to a specified size
        */
        static int winTruncate(sqlite3_file id, sqlite3_int64 nByte)
        {
            //LONG upperBits = (LONG)( ( nByte >> 32 ) & 0x7fffffff );
            //LONG lowerBits = (LONG)( nByte & 0xffffffff );
            //DWORD rc;
            //winFile* pFile = (winFile*)id;
            //DWORD error;

            Debug.Assert(id != null);
#if SQLITE_DEBUG
            //OSTRACE3( "TRUNCATE %d %lld\n", id.fs.Name, nByte );
#endif
#if SQLITE_TEST
      //SimulateIOError(return SQLITE_IOERR_TRUNCATE);  TODO --  How to implement this?
#endif
            //rc = SetFilePointer( pFile->h, lowerBits, &upperBits, FILE_BEGIN );
            //if ( rc == INVALID_SET_FILE_POINTER && ( error = GetLastError() ) != NO_ERROR )
            //{
            //  pFile->lastErrno = error;
            //  return SQLITE_IOERR_TRUNCATE;
            //}
            ///* SetEndOfFile will fail if nByte is negative */
            //if ( !SetEndOfFile( pFile->h ) )
            //{
            //  pFile->lastErrno = GetLastError();
            //  return SQLITE_IOERR_TRUNCATE;
            //}
            try
            {
                id.fs.SetLength(nByte);
            }
            catch (IOException e)
            {
#if SQLITE_SILVERLIGHT
                id.lastErrno = 1;
#else
          id.lastErrno = (u32)GetLastError();
#endif
                return SQLITE_IOERR_TRUNCATE;
            }
            return SQLITE_OK;
        }

#if SQLITE_TEST
    /*
** Count the number of fullsyncs and normal syncs.  This is used to test
** that syncs and fullsyncs are occuring at the right times.
*/
    static int sqlite3_sync_count = 0;
    static int sqlite3_fullsync_count = 0;
#endif

        /*
** Make sure all writes to a particular file are committed to disk.
*/
        static int winSync(sqlite3_file id, int flags)
        {
#if !SQLITE_NO_SYNC
            sqlite3_file pFile = (sqlite3_file)id;
            Debug.Assert(id != null);
#if SQLITE_DEBUG
            //OSTRACE3( "SYNC %d lock=%d\n", pFile.fs.GetHashCode(), pFile.locktype );
#endif
#else
UNUSED_PARAMETER(id);
#endif
#if !SQLITE_TEST
            UNUSED_PARAMETER(flags);
#else
      if ( ( flags & SQLITE_SYNC_FULL ) != 0 )
      {
        sqlite3_fullsync_count++;
      }
      sqlite3_sync_count++;
#endif
            /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
** no-op
*/
#if SQLITE_NO_SYNC
return SQLITE_OK;
#else
            pFile.fs.Flush();
            return SQLITE_OK;
            //if (FlushFileBuffers(pFile.h) != 0)
            //{
            //  return SQLITE_OK;
            //}
            //else
            //{
            //  pFile->lastErrno = (u32)GetLastError();
            //  return SQLITE_IOERR;
            //}
#endif
        }

        /*
        ** Determine the current size of a file in bytes
        */
        static int sqlite3_fileSize(sqlite3_file id, ref int pSize)
        {
            //DWORD upperBits;
            //DWORD lowerBits;
            //  sqlite3_file pFile = (sqlite3_file)id;
            //  DWORD error;
            Debug.Assert(id != null);
#if SQLITE_TEST
      //SimulateIOError(return SQLITE_IOERR_FSTAT);  TODO --  How to implement this?
#endif
            //lowerBits = GetFileSize(pFile.fs.Name, upperBits);
            //if ( ( lowerBits == INVALID_FILE_SIZE )
            //   && ( ( error = GetLastError() ) != NO_ERROR ) )
            //{
            //  pFile->lastErrno = error;
            //  return SQLITE_IOERR_FSTAT;
            //}
            //pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
            pSize = id.fs.CanRead ? (int)id.fs.Length : 0;
            return SQLITE_OK;
        }

        /*
        ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
        */
#if !LOCKFILE_FAIL_IMMEDIATELY
        const int LOCKFILE_FAIL_IMMEDIATELY = 1;
#endif

        /*
** Acquire a reader lock.
** Different API routines are called depending on whether or not this
** is Win95 or WinNT.
*/
        static int getReadLock(sqlite3_file pFile)
        {
            int res = 0;
#if SQLITE_SILVERLIGHT
            res = 1; //we got a lock :-)
#else

      if ( isNT() )
      {
        OVERLAPPED ovlp = new OVERLAPPED();
        ovlp.Offset = SHARED_FIRST;
        ovlp.OffsetHigh = 0;
        ovlp.hEvent = 0;
          res = LockFileEx( pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32() , LOCKFILE_FAIL_IMMEDIATELY,
        0, SHARED_SIZE, 0, ref ovlp );
        //try
        //{
        //  pFile.fs.Lock(SHARED_FIRST, SHARED_SIZE);
        //  res = 1;
        //}
        //catch ( IOException e )
        //{
        ////  Debug.WriteLine(e.Message );
        //  res = 0;
        //}
      }
      /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
      */
#endif

#if !SQLITE_OS_WINCE
            //else
            //{
            //  int lk;
            //  sqlite3_randomness(lk.Length, lk);
            //  pFile->sharedLockByte = (u16)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
            //  res = pFile.fs.Lock( SHARED_FIRST + pFile.sharedLockByte, 0, 1, 0);
#endif
            //}
            if (res == 0)
            {

#if SQLITE_SILVERLIGHT
                pFile.lastErrno = 1;
#else
          pFile.lastErrno = (u32)GetLastError();;
#endif

            }
            return res;
        }

        /*
        ** Undo a readlock
        */
        static int unlockReadLock(sqlite3_file pFile)
        {
            int res = 1;

#if SQLITE_SILVERLIGHT

#else
      if ( isNT() )
      {
        try
        {
          pFile.fs.Unlock( SHARED_FIRST, SHARED_SIZE ); //     res = UnlockFile(pFilE.h, SHARED_FIRST, 0, SHARED_SIZE, 0);
        }
        catch ( IOException e )
        {
          res = 0;
        }
      }
      /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
      */
#if !SQLITE_OS_WINCE
      else
      {
        Debugger.Break(); //    res = UnlockFile(pFilE.h, SHARED_FIRST + pFilE.sharedLockByte, 0, 1, 0);
      }
#endif
      if ( res == 0 )
      {
        pFile.lastErrno = (u32)GetLastError();
      }

#endif
            return res;
        }

        /*
        ** Lock the file with the lock specified by parameter locktype - one
        ** of the following:
        **
        **     (1) SHARED_LOCK
        **     (2) RESERVED_LOCK
        **     (3) PENDING_LOCK
        **     (4) EXCLUSIVE_LOCK
        **
        ** Sometimes when requesting one lock state, additional lock states
        ** are inserted in between.  The locking might fail on one of the later
        ** transitions leaving the lock state different from what it started but
        ** still short of its goal.  The following chart shows the allowed
        ** transitions and the inserted intermediate states:
        **
        **    UNLOCKED -> SHARED
        **    SHARED -> RESERVED
        **    SHARED -> (PENDING) -> EXCLUSIVE
        **    RESERVED -> (PENDING) -> EXCLUSIVE
        **    PENDING -> EXCLUSIVE
        **
        ** This routine will only increase a lock.  The winUnlock() routine
        ** erases all locks at once and returns us immediately to locking level 0.
        ** It is not possible to lower the locking level one step at a time.  You
        ** must go straight to locking level 0.
        */
        static int winLock(sqlite3_file id, int locktype)
        {
            int rc = SQLITE_OK;         /* Return code from subroutines */
            int res = 1;                /* Result of a windows lock call */
            int newLocktype;            /* Set pFile.locktype to this value before exiting */
            bool gotPendingLock = false;/* True if we acquired a PENDING lock this time */
            sqlite3_file pFile = (sqlite3_file)id;
            DWORD error = NO_ERROR;

#if SQLITE_SILVERLIGHT
            return SQLITE_OK; //sure, we got a lock, honest :-)
#else

      Debug.Assert( id != null );
#if SQLITE_DEBUG
      OSTRACE5( "LOCK %d %d was %d(%d)\n",
      pFile.fs.GetHashCode(), locktype, pFile.locktype, pFile.sharedLockByte );
#endif
      /* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
** sqlite3OsEnterMutex() hasn't been called yet.
*/
      if ( pFile.locktype >= locktype )
      {
        return SQLITE_OK;
      }

      /* Make sure the locking sequence is correct
      */
      Debug.Assert( pFile.locktype != NO_LOCK || locktype == SHARED_LOCK );
      Debug.Assert( locktype != PENDING_LOCK );
      Debug.Assert( locktype != RESERVED_LOCK || pFile.locktype == SHARED_LOCK );

      /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
      ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
      ** the PENDING_LOCK byte is temporary.
      */
      newLocktype = pFile.locktype;
      if ( pFile.locktype == NO_LOCK
      || ( ( locktype == EXCLUSIVE_LOCK )
      && ( pFile.locktype == RESERVED_LOCK ) )
      )
      {
        int cnt = 3;
        res = 0;
        while (cnt-- > 0 && (res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), PENDING_BYTE, 0, 1, 0)) == 0)
        {
          /* Try 3 times to get the pending lock.  The pending lock might be
          ** held by another reader process who will release it momentarily.
          */
#if SQLITE_DEBUG
          OSTRACE2( "could not get a PENDING lock. cnt=%d\n", cnt );
#endif
          Thread.Sleep( 1 );
        }
        gotPendingLock = ( res != 0 );
        if ( 0 == res )
        {
          error = (u32)GetLastError();
        }
      }

      /* Acquire a shared lock
      */
      if ( locktype == SHARED_LOCK && res != 0 )
      {
        Debug.Assert( pFile.locktype == NO_LOCK );
        res = getReadLock( pFile );
        if ( res != 0 )
        {
          newLocktype = SHARED_LOCK;
        }
        else
        {
          error = (u32)GetLastError();
        }
      }

      /* Acquire a RESERVED lock
      */
      if ( ( locktype == RESERVED_LOCK ) && res != 0 )
      {
        Debug.Assert( pFile.locktype == SHARED_LOCK );
        res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), RESERVED_BYTE, 0, 1, 0);
        if ( res != 0 )
        {
          newLocktype = RESERVED_LOCK;
        }
        else
        {
          error = (u32)GetLastError();
        }
      }

      /* Acquire a PENDING lock
      */
      if ( locktype == EXCLUSIVE_LOCK && res != 0 )
      {
        newLocktype = PENDING_LOCK;
        gotPendingLock = false;
      }

      /* Acquire an EXCLUSIVE lock
      */
      if ( locktype == EXCLUSIVE_LOCK && res != 0 )
      {
        Debug.Assert( pFile.locktype >= SHARED_LOCK );
        res = unlockReadLock( pFile );
#if SQLITE_DEBUG
        OSTRACE2( "unreadlock = %d\n", res );
#endif
        res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), SHARED_FIRST, 0, SHARED_SIZE, 0);
        if ( res != 0 )
        {
          newLocktype = EXCLUSIVE_LOCK;
        }
        else
        {
          error = (u32)GetLastError();
#if SQLITE_DEBUG
          OSTRACE2( "error-code = %d\n", error );
#endif
          getReadLock( pFile );
        }
      }

      /* If we are holding a PENDING lock that ought to be released, then
      ** release it now.
      */
      if ( gotPendingLock && locktype == SHARED_LOCK )
      {
        pFile.fs.Unlock( PENDING_BYTE, 1 );
      }

      /* Update the state of the lock has held in the file descriptor then
      ** return the appropriate result code.
      */
      if ( res != 0 )
      {
        rc = SQLITE_OK;
      }
      else
      {
#if SQLITE_DEBUG
        OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile.fs.GetHashCode(),
        locktype, newLocktype );
#endif
        pFile.lastErrno = error;
        rc = SQLITE_BUSY;
      }
      pFile.locktype = (u8)newLocktype;
      return rc;

#endif //SQLITE_SILVERLIGHT
        }

        /*
        ** This routine checks if there is a RESERVED lock held on the specified
        ** file by this or any other process. If such a lock is held, return
        ** non-zero, otherwise zero.
        */
        static int winCheckReservedLock(sqlite3_file id, ref int pResOut)
        {
            int rc;
            sqlite3_file pFile = (sqlite3_file)id;
            Debug.Assert(id != null);

#if ! SQLITE_SILVERLIGHT

      if ( pFile.locktype >= RESERVED_LOCK )
      {
        rc = 1;
#if SQLITE_DEBUG
        OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile.fs.Name, rc );
#endif
      }
      else
      {
        try
        {
          id.fs.Lock( RESERVED_BYTE, 1 );
          id.fs.Unlock( RESERVED_BYTE, 1 );
          rc = 1;
        }
        catch ( IOException e )
        { rc = 0; }
        rc = 1 - rc; // !rc
#if SQLITE_DEBUG
        OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile.fs.GetHashCode(), rc );
#endif
      }
      pResOut = rc;

#endif

            return SQLITE_OK;
        }

        /*
        ** Lower the locking level on file descriptor id to locktype.  locktype
        ** must be either NO_LOCK or SHARED_LOCK.
        **
        ** If the locking level of the file descriptor is already at or below
        ** the requested locking level, this routine is a no-op.
        **
        ** It is not possible for this routine to fail if the second argument
        ** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
        ** might return SQLITE_IOERR;
        */
        static int winUnlock(sqlite3_file id, int locktype)
        {
            int type;
            sqlite3_file pFile = (sqlite3_file)id;
            int rc = SQLITE_OK;
            Debug.Assert(pFile != null);
            Debug.Assert(locktype <= SHARED_LOCK);

#if SQLITE_SILVERLIGHT

#else

#if SQLITE_DEBUG
      OSTRACE5( "UNLOCK %d to %d was %d(%d)\n", pFile.fs.GetHashCode(), locktype,
      pFile.locktype, pFile.sharedLockByte );
#endif
      type = pFile.locktype;
      if ( type >= EXCLUSIVE_LOCK )
      {
        id.fs.Unlock( SHARED_FIRST, SHARED_SIZE ); // UnlockFile(pFilE.h, SHARED_FIRST, 0, SHARED_SIZE, 0);
        if ( locktype == SHARED_LOCK && getReadLock( pFile ) == 0 )
        {
          /* This should never happen.  We should always be able to
          ** reacquire the read lock */
          rc = SQLITE_IOERR_UNLOCK;
        }
      }
      if ( type >= RESERVED_LOCK )
      {
        try
        {
          id.fs.Unlock( RESERVED_BYTE, 1 );// UnlockFile(pFilE.h, RESERVED_BYTE, 0, 1, 0);
        }
        catch ( IOException e ) { }
      }
      if ( locktype == NO_LOCK && type >= SHARED_LOCK )
      {
        unlockReadLock( pFile );
      }
      if ( type >= PENDING_LOCK )
      {
        try
        {
          id.fs.Unlock( PENDING_BYTE, 1 );//    UnlockFile(pFilE.h, PENDING_BYTE, 0, 1, 0);
        }
        catch ( IOException e )
        { }
      }
      pFile.locktype = (u8)locktype;
#endif
            return rc;
        }

        /*
        ** Control and query of the open file handle.
        */
        static int winFileControl(sqlite3_file id, int op, ref int pArg)
        {
            switch (op)
            {
                case SQLITE_FCNTL_LOCKSTATE:
                    {
                        pArg = ((sqlite3_file)id).locktype;
                        return SQLITE_OK;
                    }
                case SQLITE_LAST_ERRNO:
                    {
                        pArg = (int)((sqlite3_file)id).lastErrno;
                        return SQLITE_OK;
                    }
            }
            return SQLITE_ERROR;
        }

        /*
        ** Return the sector size in bytes of the underlying block device for
        ** the specified file. This is almost always 512 bytes, but may be
        ** larger for some devices.
        **
        ** SQLite code assumes this function cannot fail. It also assumes that
        ** if two files are created in the same file-system directory (i.e.
        ** a database and its journal file) that the sector size will be the
        ** same for both.
        */
        static int winSectorSize(sqlite3_file id)
        {
            Debug.Assert(id != null);
            return (int)(id.sectorSize);
        }

        /*
        ** Return a vector of device characteristics.
        */
        static int winDeviceCharacteristics(sqlite3_file id)
        {
            UNUSED_PARAMETER(id);
            return 0;
        }

        /*
        ** This vector defines all the methods that can operate on an
        ** sqlite3_file for win32.
        */
        static sqlite3_io_methods winIoMethod = new sqlite3_io_methods(
        1,                        /* iVersion */
        (dxClose)winClose,
        (dxRead)winRead,
        (dxWrite)winWrite,
        (dxTruncate)winTruncate,
        (dxSync)winSync,
        (dxFileSize)sqlite3_fileSize,
        (dxLock)winLock,
        (dxUnlock)winUnlock,
        (dxCheckReservedLock)winCheckReservedLock,
        (dxFileControl)winFileControl,
        (dxSectorSize)winSectorSize,
        (dxDeviceCharacteristics)winDeviceCharacteristics
        );

        /***************************************************************************
        ** Here ends the I/O methods that form the sqlite3_io_methods object.
        **
        ** The next block of code implements the VFS methods.
        ****************************************************************************/

        /*
        ** Convert a UTF-8 filename into whatever form the underlying
        ** operating system wants filenames in.  Space to hold the result
        ** is obtained from malloc and must be freed by the calling
        ** function.
        */
        static string convertUtf8Filename(string zFilename)
        {
            return zFilename;
            // string zConverted = "";
            //if (isNT())
            //{
            //  zConverted = utf8ToUnicode(zFilename);
            /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
            */
#if !SQLITE_OS_WINCE
            //}
            //else
            //{
            //  zConverted = utf8ToMbcs(zFilename);
#endif
            //}
            /* caller will handle out of memory */
            //return zConverted;
        }

        /*
        ** Create a temporary file name in zBuf.  zBuf must be big enough to
        ** hold at pVfs.mxPathname characters.
        */
        static int getTempname(int nBuf, StringBuilder zBuf)
        {
            const string zChars = "abcdefghijklmnopqrstuvwxyz0123456789";
            //static char zChars[] =
            //  "abcdefghijklmnopqrstuvwxyz"
            //  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            //  "0123456789";
            //size_t i, j;
            //char zTempPath[MAX_PATH+1];
            //if( sqlite3_temp_directory ){
            //  sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
            //}else if( isNT() ){
            //  char *zMulti;
            //  WCHAR zWidePath[MAX_PATH];
            //  GetTempPathW(MAX_PATH-30, zWidePath);
            //  zMulti = unicodeToUtf8(zWidePath);
            //  if( zMulti ){
            //    sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
            //    free(zMulti);
            //  }else{
            //    return SQLITE_NOMEM;
            //  }
            /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
            ** Since the ASCII version of these Windows API do not exist for WINCE,
            ** it's important to not reference them for WINCE builds.
            */
#if !SQLITE_OS_WINCE
            //}else{
            //  char *zUtf8;
            //  char zMbcsPath[MAX_PATH];
            //  GetTempPathA(MAX_PATH-30, zMbcsPath);
            //  zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
            //  if( zUtf8 ){
            //    sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
            //    free(zUtf8);
            //  }else{
            //    return SQLITE_NOMEM;
            //  }
#endif
            //}

            StringBuilder zRandom = new StringBuilder(20);
            i64 iRandom = 0;
            for (int i = 0; i < 20; i++)
            {
                sqlite3_randomness(1, ref iRandom);
                zRandom.Append((char)zChars[(int)(iRandom % (zChars.Length - 1))]);
            }
            //  zBuf[j] = 0;
            zBuf.Append(Path.GetTempPath() + SQLITE_TEMP_FILE_PREFIX + zRandom.ToString());
            //for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
            //zTempPath[i] = 0;
            //sqlite3_snprintf(nBuf-30, zBuf,
            //                 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
            //j = sqlite3Strlen30(zBuf);
            //sqlite3_randomness(20, zBuf[j]);
            //for(i=0; i<20; i++, j++){
            //  zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
            //}
            //zBuf[j] = 0;

#if SQLITE_DEBUG
            OSTRACE2("TEMP FILENAME: %s\n", zBuf.ToString());
#endif
            return SQLITE_OK;
        }

        /*
        ** The return value of getLastErrorMsg
        ** is zero if the error message fits in the buffer, or non-zero
        ** otherwise (if the message was truncated).
        */
        static int getLastErrorMsg(int nBuf, ref string zBuf)
        {
#if SQLITE_SILVERLIGHT
            zBuf = "Unknown error";
            return 0;
#else

        
        int error = GetLastError();


#if SQLITE_OS_WINCE
sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
#else
      /* FormatMessage returns 0 on failure.  Otherwise it
** returns the number of TCHARs written to the output
** buffer, excluding the terminating null char.
*/
      int iDummy = 0;
      object oDummy = null;
      if ( 00 == FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM,
      ref oDummy,
      error,
      0,
      zBuf,
      nBuf - 1,
      ref iDummy ) )
      {
        sqlite3_snprintf( nBuf, ref zBuf, "OsError 0x%x (%u)", error, error );
      }
#endif

      return 0;

                 
#endif
        }

        /*
        ** Open a file.
        */
        static int winOpen(
        sqlite3_vfs pVfs,       /* Not used */
        string zName,           /* Name of the file (UTF-8) */
        ref sqlite3_file pFile, /* Write the SQLite file handle here */
        int flags,              /* Open mode flags */
        ref int pOutFlags       /* Status return flags */
        )
        {
            //HANDLE h;

            FileAccess dwDesiredAccess;
            FileShare dwShareMode;
            FileMode dwCreationDisposition;
#if SQLITE_SILVERLIGHT
            IsolatedStorageFileStream fs = null;
            IsolatedStorageFile theStore = null;

#else
        FileStream fs = null;
      FileOptions dwFlagsAndAttributes;
#endif
#if SQLITE_OS_WINCE
int isTemp = 0;
#endif
            //winFile* pFile = (winFile*)id;
            string zConverted;                 /* Filename in OS encoding */
            string zUtf8Name = zName;    /* Filename in UTF-8 encoding */
            StringBuilder zTmpname = new StringBuilder(MAX_PATH + 1);        /* Buffer used to create temp filename */

            Debug.Assert(pFile != null);
            UNUSED_PARAMETER(pVfs);

            /* If the second argument to this function is NULL, generate a 
            ** temporary file name to use 
            */
            if (String.IsNullOrEmpty(zUtf8Name))
            {
                int rc = getTempname(MAX_PATH + 1, zTmpname);
                if (rc != SQLITE_OK)
                {
                    return rc;
                }
                zUtf8Name = zTmpname.ToString();
            }

            // /* Convert the filename to the system encoding. */
            zConverted = zUtf8Name;// convertUtf8Filename( zUtf8Name );
            if (String.IsNullOrEmpty(zConverted))
            {
                return SQLITE_NOMEM;
            }

            if ((flags & SQLITE_OPEN_READWRITE) != 0)
            {
                dwDesiredAccess = FileAccess.Read | FileAccess.Write; // GENERIC_READ | GENERIC_WRITE;
            }
            else
            {
                dwDesiredAccess = FileAccess.Read; // GENERIC_READ;
            }
            /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is 
            ** created. SQLite doesn't use it to indicate "exclusive access" 
            ** as it is usually understood.
            */
            Debug.Assert(0 == (flags & SQLITE_OPEN_EXCLUSIVE) || (flags & SQLITE_OPEN_CREATE) != 0);
            if ((flags & SQLITE_OPEN_EXCLUSIVE) != 0)
            {
                /* Creates a new file, only if it does not already exist. */
                /* If the file exists, it fails. */
                dwCreationDisposition = FileMode.CreateNew;// CREATE_NEW;
            }
            else if ((flags & SQLITE_OPEN_CREATE) != 0)
            {
                /* Open existing file, or create if it doesn't exist */
                dwCreationDisposition = FileMode.OpenOrCreate;// OPEN_ALWAYS;
            }
            else
            {
                /* Opens a file, only if it exists. */
                dwCreationDisposition = FileMode.Open;//OPEN_EXISTING;
            }
            dwShareMode = FileShare.Read | FileShare.Write;// FILE_SHARE_READ | FILE_SHARE_WRITE;
            if ((flags & SQLITE_OPEN_DELETEONCLOSE) != 0)
            {
#if SQLITE_OS_WINCE 
dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
isTemp = 1;
#elif SQLITE_SILVERLIGHT

#else
        dwFlagsAndAttributes = FileOptions.DeleteOnClose; // FILE_ATTRIBUTE_TEMPORARY
        //| FILE_ATTRIBUTE_HIDDEN
        //| FILE_FLAG_DELETE_ON_CLOSE;
#endif
            }
            else
            {
#if ! SQLITE_SILVERLIGHT
        dwFlagsAndAttributes = FileOptions.None; // FILE_ATTRIBUTE_NORMAL;
#endif
            }
            /* Reports from the internet are that performance is always
            ** better if FILE_FLAG_RANDOM_ACCESS is used.  Ticket #2699. */
#if SQLITE_OS_WINCE
dwFlagsAndAttributes |= FileOptions.RandomAccess; // FILE_FLAG_RANDOM_ACCESS;
#endif
            if (isNT())
            {
                #region COMMENTED OUT Code
                //h = CreateFileW((WCHAR*)zConverted,
                //   dwDesiredAccess,
                //   dwShareMode,
                //   NULL,
                //   dwCreationDisposition,
                //   dwFlagsAndAttributes,
                //   NULL
                //);
                #endregion
                try
                {
#if SQLITE_SILVERLIGHT   // Declared in Unit Test project

            theStore = GetUserStoreForApplication();

            fs = new System.IO.IsolatedStorage.IsolatedStorageFileStream(zConverted, dwCreationDisposition, dwDesiredAccess, dwShareMode, theStore);
#else
            fs = new FileStream( zConverted, dwCreationDisposition, dwDesiredAccess, dwShareMode, 1024, dwFlagsAndAttributes );
#endif
#if SQLITE_DEBUG
                    //OSTRACE3( "OPEN %d (%s)\n", fs.GetHashCode(), fs.Name );
#endif
                }
                catch (Exception e)
                { }

                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
                ** Since the ASCII version of these Windows API do not exist for WINCE,
                ** it's important to not reference them for WINCE builds.
                */
#if !SQLITE_OS_WINCE
            }
            else
            {
                Debugger.Break(); // Not NT
                //h = CreateFileA((char*)zConverted,
                //   dwDesiredAccess,
                //   dwShareMode,
                //   NULL,
                //   dwCreationDisposition,
                //   dwFlagsAndAttributes,
                //   NULL
                //);
#endif
            }
#if SQLITE_SILVERLIGHT
            if (fs == null) //(h == INVALID_HANDLE_VALUE)

#else
             if ( fs == null || fs.SafeFileHandle.IsInvalid ) //(h == INVALID_HANDLE_VALUE)

#endif
            {
                //        free(zConverted);
                if ((flags & SQLITE_OPEN_READWRITE) != 0)
                {
                    return winOpen(pVfs, zName, ref pFile,
                    ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE), ref pOutFlags);
                }
                else
                {
                    return SQLITE_CANTOPEN;
                }
            }
            //if ( pOutFlags )
            //{
            if ((flags & SQLITE_OPEN_READWRITE) != 0)
            {
                pOutFlags = SQLITE_OPEN_READWRITE;
            }
            else
            {
                pOutFlags = SQLITE_OPEN_READONLY;
            }
            //}
            pFile = new sqlite3_file(); // memset(pFile, 0, sizeof(*pFile));
            pFile.pMethods = winIoMethod;
            pFile.fs = fs;
            pFile.lastErrno = NO_ERROR;
            pFile.sectorSize = (ulong)getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
(SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
&& !winceCreateLock(zName, pFile)
){
CloseHandle(h);
free(zConverted);
return SQLITE_CANTOPEN;
}
if( isTemp ){
pFile.zDeleteOnClose = zConverted;
}else
#endif
            {
                // free(zConverted);
            }
#if SQLITE_TEST
      OpenCounter( +1 );
#endif
            return SQLITE_OK;
        }

        /*
        ** Delete the named file.
        **
        ** Note that windows does not allow a file to be deleted if some other
        ** process has it open.  Sometimes a virus scanner or indexing program
        ** will open a journal file shortly after it is created in order to do
        ** whatever it does.  While this other process is holding the
        ** file open, we will be unable to delete it.  To work around this
        ** problem, we delay 100 milliseconds and try to delete again.  Up
        ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
        ** up and returning an error.
        */
        static int MX_DELETION_ATTEMPTS = 5;
        static int winDelete(
        sqlite3_vfs pVfs,         /* Not used on win32 */
        string zFilename,         /* Name of file to delete */
        int syncDir               /* Not used on win32 */
        )
        {
            int cnt = 0;
            int rc;
            int error;
            UNUSED_PARAMETER(pVfs);
            UNUSED_PARAMETER(syncDir);
            string zConverted = convertUtf8Filename(zFilename);
            if (zConverted == null || zConverted == "")
            {
                return SQLITE_NOMEM;
            }
#if SQLITE_TEST
      //SimulateIOError(return SQLITE_IOERR_DELETE);  TODO --  How to implement this?
#endif
            if (isNT())
            {
                do
                //  DeleteFileW(zConverted);
                //}while(   (   ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES)
                //           || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
                //       && (++cnt < MX_DELETION_ATTEMPTS)
                //       && (Sleep(100), 1) );
                {
#if SQLITE_SILVERLIGHT
                    if (!ExistsFile(zFilename))
#else
            if ( !File.Exists( zFilename ) )
#endif
                    {
                        rc = SQLITE_IOERR;
                        break;
                    }
                    try
                    {

#if SQLITE_SILVERLIGHT
                        DeleteFile(zConverted);
#else
               File.Delete( zConverted );
#endif
                        rc = SQLITE_OK;
                    }
                    catch (IOException e)
                    {
                        rc = SQLITE_IOERR;
                        Thread.Sleep(100);
                    }
                } while (rc != SQLITE_OK && ++cnt < MX_DELETION_ATTEMPTS);
                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
                ** Since the ASCII version of these Windows API do not exist for WINCE,
                ** it's important to not reference them for WINCE builds.
                */
#if !SQLITE_OS_WINCE
            }
            else
            {
                do
                {
                    //DeleteFileA( zConverted );
                    //}while(   (   ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES)
                    //           || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
                    //       && (cnt++ < MX_DELETION_ATTEMPTS)
                    //       && (Sleep(100), 1) );
                    if (!File.Exists(zFilename))
                    {
                        rc = SQLITE_IOERR;
                        break;
                    }
                    try
                    {
                        File.Delete(zConverted);
                        rc = SQLITE_OK;
                    }
                    catch (IOException e)
                    {
                        rc = SQLITE_IOERR;
                        Thread.Sleep(100);
                    }
                } while (rc != SQLITE_OK && cnt++ < MX_DELETION_ATTEMPTS);
#endif
            }
            //free(zConverted);
#if SQLITE_DEBUG
            OSTRACE2("DELETE \"%s\"\n", zFilename);
#endif
            //return ( ( rc == INVALID_FILE_ATTRIBUTES )
            //&& ( error == ERROR_FILE_NOT_FOUND ) ) ? SQLITE_OK : SQLITE_IOERR_DELETE;
            return rc;
        }

#if SQLITE_SILVERLIGHT
        /*
    ** Check the existence and status of a file.
    */
        static int winAccess(
        sqlite3_vfs pVfs,       /* Not used on win32 */
        string zFilename,       /* Name of file to check */
        int flags,              /* Type of test to make on this file */
        ref int pResOut         /* OUT: Result */
        )
        {
            FileAttributes attr = 0; // DWORD attr;
            int rc = 0;
            //  void *zConverted = convertUtf8Filename(zFilename);
            UNUSED_PARAMETER(pVfs);
            //  if( zConverted==0 ){
            //    return SQLITE_NOMEM;
            //  }
            //if ( isNT() )
            //{
            //
            // Do a quick test to prevent the try/catch block

            using (var theStore = GetUserStoreForApplication())
            {
                if (flags == SQLITE_ACCESS_EXISTS)
                {
                    pResOut = theStore.FileExists(zFilename) ? 1 : 0;
                    return SQLITE_OK;
                }
                //
                try
                {
                    if (theStore.DirectoryExists(zFilename))
                    {
                        StringBuilder zTmpname = new StringBuilder(255);        /* Buffer used to create temp filename */
                        getTempname(256, zTmpname);

                        string zTempFilename;
                        zTempFilename = zTmpname.ToString();//( SQLITE_TEMP_FILE_PREFIX.Length + 1 );
                        try
                        {
                            IsolatedStorageFileStream fs = theStore.CreateFile(zTempFilename);
                            fs.Close();
                            theStore.DeleteFile(zTempFilename);
                            attr = FileAttributes.Normal;
                        }
                        catch (IOException e) { attr = FileAttributes.ReadOnly; }
                    }

                }
                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
                ** Since the ASCII version of these Windows API do not exist for WINCE,
                ** it's important to not reference them for WINCE builds.
                */
#if !SQLITE_OS_WINCE
                //}
                //else
                //{
                //  attr = GetFileAttributesA( (char*)zConverted );
#endif
                //}
                catch (IOException e)
                { }
                //  free(zConverted);
                switch (flags)
                {
                    case SQLITE_ACCESS_READ:
                        rc = 0;
                        break;
                    case SQLITE_ACCESS_READWRITE:
                        rc = 0;
                        break;
                    default:
                        Debug.Assert("" == "Invalid flags argument");
                        rc = 0;
                        break;
                }

            } //end using theStore
            pResOut = rc;
            return SQLITE_OK;
        }

#else

    /*
    ** Check the existence and status of a file.
    */
    static int winAccess(
    sqlite3_vfs pVfs,       /* Not used on win32 */
    string zFilename,       /* Name of file to check */
    int flags,              /* Type of test to make on this file */
    ref int pResOut         /* OUT: Result */
    )
    {
      FileAttributes attr = 0; // DWORD attr;
      int rc = 0;
      //  void *zConverted = convertUtf8Filename(zFilename);
      UNUSED_PARAMETER( pVfs );
      //  if( zConverted==0 ){
      //    return SQLITE_NOMEM;
      //  }
      //if ( isNT() )
      //{
      //
      // Do a quick test to prevent the try/catch block
      if ( flags == SQLITE_ACCESS_EXISTS )
      {
        pResOut = File.Exists( zFilename ) ? 1 : 0;
        return SQLITE_OK;
      }
      //
      try
      {
        attr = File.GetAttributes( zFilename );// GetFileAttributesW( (WCHAR*)zConverted );
        if ( attr == FileAttributes.Directory )
        {
          StringBuilder zTmpname = new StringBuilder( 255 );        /* Buffer used to create temp filename */
          getTempname( 256, zTmpname );

          string zTempFilename;
          zTempFilename = zTmpname.ToString();//( SQLITE_TEMP_FILE_PREFIX.Length + 1 );
          try
          {
            FileStream fs = File.Create( zTempFilename, 1, FileOptions.DeleteOnClose );
            fs.Close();
            attr = FileAttributes.Normal;
          }
          catch ( IOException e ) { attr = FileAttributes.ReadOnly; }
        }
      }
      /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
      ** Since the ASCII version of these Windows API do not exist for WINCE,
      ** it's important to not reference them for WINCE builds.
      */
#if !SQLITE_OS_WINCE
      //}
      //else
      //{
      //  attr = GetFileAttributesA( (char*)zConverted );
#endif
      //}
      catch ( IOException e )
      { }
      //  free(zConverted);
      switch ( flags )
      {
        case SQLITE_ACCESS_READ:
        case SQLITE_ACCESS_EXISTS:
          rc = attr != 0 ? 1 : 0;// != INVALID_FILE_ATTRIBUTES;
          break;
        case SQLITE_ACCESS_READWRITE:
          rc = attr == 0 ? 0 : (int)( attr & FileAttributes.ReadOnly ) != 0 ? 0 : 1; //FILE_ATTRIBUTE_READONLY ) == 0;
          break;
        default:
          Debug.Assert( "" == "Invalid flags argument" );
          rc = 0;
          break;
      }
      pResOut = rc;
      return SQLITE_OK;
    }

#endif

        /*
    ** Turn a relative pathname into a full pathname.  Write the full
    ** pathname into zOut[].  zOut[] will be at least pVfs.mxPathname
    ** bytes in size.
    */
        static int winFullPathname(
        sqlite3_vfs pVfs,             /* Pointer to vfs object */
        string zRelative,             /* Possibly relative input path */
        int nFull,                    /* Size of output buffer in bytes */
        StringBuilder zFull           /* Output buffer */
        )
        {

#if SQLITE_SILVERLIGHT
            zFull.Append(zRelative);

            // will happen on exit; was   free(zOut);
            return SQLITE_OK;

#endif

#if __CYGWIN__
UNUSED_PARAMETER(nFull);
cygwin_conv_to_full_win32_path(zRelative, zFull);
return SQLITE_OK;
#endif

#if SQLITE_OS_WINCE
UNUSED_PARAMETER(nFull);
/* WinCE has no concept of a relative pathname, or so I am told. */
sqlite3_snprintf(pVfs.mxPathname, zFull, "%s", zRelative);
return SQLITE_OK;
#endif

#if !SQLITE_OS_WINCE && !__CYGWIN__
            int nByte;
            //string  zConverted;
            string zOut = null;
            UNUSED_PARAMETER(nFull);
            //convertUtf8Filename(zRelative));
            if (isNT())
            {
                //string zTemp;
                //nByte = GetFullPathNameW( zConverted, 0, 0, 0) + 3;
                //zTemp = malloc( nByte*sizeof(zTemp[0]) );
                //if( zTemp==0 ){
                //  free(zConverted);
                //  return SQLITE_NOMEM;
                //}
                //zTemp = GetFullPathNameW(zConverted, nByte, zTemp, 0);
                // will happen on exit; was   free(zConverted);
                try
                {
                    zOut = Path.GetFullPath(zRelative); // was unicodeToUtf8(zTemp);
                }
                catch (IOException e)
                { zOut = zRelative; }
                // will happen on exit; was   free(zTemp);
                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
                ** Since the ASCII version of these Windows API do not exist for WINCE,
                ** it's important to not reference them for WINCE builds.
                */
#if !SQLITE_OS_WINCE
            }
            else
            {
                Debugger.Break(); // -- Not Running under NT
                //string zTemp;
                //nByte = GetFullPathNameA(zConverted, 0, 0, 0) + 3;
                //zTemp = malloc( nByte*sizeof(zTemp[0]) );
                //if( zTemp==0 ){
                //  free(zConverted);
                //  return SQLITE_NOMEM;
                //}
                //GetFullPathNameA( zConverted, nByte, zTemp, 0);
                // free(zConverted);
                //zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
                // free(zTemp);
#endif
            }
            if (zOut != null)
            {
                // sqlite3_snprintf(pVfs.mxPathname, zFull, "%s", zOut);
                if (zFull.Length > pVfs.mxPathname) zFull.Length = pVfs.mxPathname;
                zFull.Append(zOut);

                // will happen on exit; was   free(zOut);
                return SQLITE_OK;
            }
            else
            {
                return SQLITE_NOMEM;
            }
#endif
        }


        /*
        ** Get the sector size of the device used to store
        ** file.
        */
        static int getSectorSize(
        sqlite3_vfs pVfs,
        string zRelative     /* UTF-8 file name */
        )
        {

#if SQLITE_SILVERLIGHT
            return SQLITE_DEFAULT_SECTOR_SIZE;
#else
       
        int bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
      StringBuilder zFullpath = new StringBuilder( MAX_PATH + 1 );
      int rc;
      bool dwRet = false;
      int dwDummy = 0;

      /*
      ** We need to get the full path name of the file
      ** to get the drive letter to look up the sector
      ** size.
      */
      rc = winFullPathname( pVfs, zRelative, MAX_PATH, zFullpath );
      if ( rc == SQLITE_OK )
      {
        StringBuilder zConverted = new StringBuilder( convertUtf8Filename( zFullpath.ToString() ) );
        if ( zConverted.Length != 0 )
        {
          if ( isNT() )
          {
            /* trim path to just drive reference */
            //for ( ; *p ; p++ )
            //{
            //  if ( *p == '\\' )
            //  {
            //    *p = '\0';
            //    break;
            //  }
            //}
            int i;
            for ( i = 0 ; i < zConverted.Length && i < MAX_PATH ; i++ )
            {
              if ( zConverted[i] == '\\' )
              {
                i++;
                break;
              }
            }
            zConverted.Length = i;
            dwRet = GetDiskFreeSpace( zConverted,
                 ref dwDummy,
                 ref bytesPerSector,
                 ref dwDummy,
                 ref dwDummy );
            //#if !SQLITE_OS_WINCE
            //}else{
            //  /* trim path to just drive reference */
            //  CHAR* p = (CHAR*)zConverted;
            //  for ( ; *p ; p++ )
            //  {
            //    if ( *p == '\\' )
            //    {
            //      *p = '\0';
            //      break;
            //    }
            //  }
            //        dwRet = GetDiskFreeSpaceA((CHAR*)zConverted,
            //                                  dwDummy,
            //                                  ref bytesPerSector,
            //                                  dwDummy,
            //                                  dwDummy );
            //#endif
          }
          //free(zConverted);
        }
        if ( !dwRet )
        {
          bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
        }
      }
      return (int)bytesPerSector;
#endif
        }

#if !SQLITE_OMIT_LOAD_EXTENSION
        /*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
        /*
        ** Interfaces for opening a shared library, finding entry points
        ** within the shared library, and closing the shared library.
        */
        //static void *winDlOpen(sqlite3_vfs pVfs, string zFilename){
        //  HANDLE h;
        //  void *zConverted = convertUtf8Filename(zFilename);
        //  UNUSED_PARAMETER(pVfs);
        //  if( zConverted==0 ){
        //    return 0;
        //  }
        //  if( isNT() ){
        //    h = LoadLibraryW((WCHAR*)zConverted);
        /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
        ** Since the ASCII version of these Windows API do not exist for WINCE,
        ** it's important to not reference them for WINCE builds.
        */
#if !SQLITE_OS_WINCE
        //  }else{
        //    h = LoadLibraryA((char*)zConverted);
#endif
        //  }
        //  free(zConverted);
        //  return (void*)h;
        //}
        //static void winDlError(sqlite3_vfs pVfs, int nBuf, char *zBufOut){
        //  UNUSED_PARAMETER(pVfs);
        //  getLastErrorMsg(nBuf, zBufOut);
        //}
        //    static object winDlSym(sqlite3_vfs pVfs, HANDLE pHandle, String zSymbol){
        //  UNUSED_PARAMETER(pVfs);
        //#if SQLITE_OS_WINCE
        //      /* The GetProcAddressA() routine is only available on wince. */
        //      return GetProcAddressA((HANDLE)pHandle, zSymbol);
        //#else
        //     /* All other windows platforms expect GetProcAddress() to take
        //      ** an Ansi string regardless of the _UNICODE setting */
        //      return GetProcAddress((HANDLE)pHandle, zSymbol);
        //#endif
        //   }
        //    static void winDlClose( sqlite3_vfs pVfs, HANDLE pHandle )
        //   {
        //  UNUSED_PARAMETER(pVfs);
        //     FreeLibrary((HANDLE)pHandle);
        //   }
        //TODO -- Fix This
        static HANDLE winDlOpen(sqlite3_vfs vfs, string zFilename) { return new HANDLE(); }
        static int winDlError(sqlite3_vfs vfs, int nByte, ref string zErrMsg) { return 0; }
        static HANDLE winDlSym(sqlite3_vfs vfs, HANDLE data, string zSymbol) { return new HANDLE(); }
        static int winDlClose(sqlite3_vfs vfs, HANDLE data) { return 0; }
#else // * if SQLITE_OMIT_LOAD_EXTENSION is defined: */
static object winDlOpen(ref sqlite3_vfs vfs, string zFilename) { return null; }
static int winDlError(ref sqlite3_vfs vfs, int nByte, ref string zErrMsg) { return 0; }
static object winDlSym(ref sqlite3_vfs vfs, object data, string zSymbol) { return null; }
static int winDlClose(ref sqlite3_vfs vfs, object data) { return 0; }
#endif


        /*
** Write up to nBuf bytes of randomness into zBuf.
*/

#if ! SQLITE_SILVERLIGHT

    [StructLayout( LayoutKind.Explicit, Size = 16, CharSet = CharSet.Ansi )]
    public class _SYSTEMTIME
    {
      [FieldOffset( 0 )]
      public u32 byte_0_3;
      [FieldOffset( 4 )]
      public u32 byte_4_7;
      [FieldOffset( 8 )]
      public u32 byte_8_11;
      [FieldOffset( 12 )]
      public u32 byte_12_15;
    }
    [DllImport( "kernel32.dll" )]
    public static extern void GetSystemTime( [MarshalAs( UnmanagedType.LPStruct )]_SYSTEMTIME stSYSTEMTIME );
    [DllImport( "Kernel32.dll" )]
    private static extern bool QueryPerformanceCounter( out long lpPerformanceCount );

#endif

        static int winRandomness(sqlite3_vfs pVfs, int nBuf, ref byte[] zBuf)
        {
            int n = 0;
            UNUSED_PARAMETER(pVfs);
#if (SQLITE_TEST)
      n = nBuf;
      Array.Clear( zBuf, 0, n );// memset( zBuf, 0, nBuf );
#else

#if SQLITE_SILVERLIGHT
            System.DateTime d = System.DateTime.Now;

            put32bits(zBuf, 0, d.Millisecond);
            put32bits(zBuf, 4, d.Second);
            put32bits(zBuf, 8, (int)d.Ticks);
            put32bits(zBuf, 12, d.Hour);
            ;// memcpy(&zBuf[n], x, sizeof(x))
            n += 16;// sizeof(x);

#else
SYSTEMTIME SYSTEMTIME = new _SYSTEMTIME();
if ( Marshal.SizeOf( SYSTEMTIME ) <= nBuf - n )
{
GetSystemTime( SYSTEMTIME );
put32bits( zBuf, 0, SYSTEMTIME.byte_0_3 );
put32bits( zBuf, 4, SYSTEMTIME.byte_4_7 );
put32bits( zBuf, 8, SYSTEMTIME.byte_8_11 );
put32bits( zBuf, 12, SYSTEMTIME.byte_12_15 );
;// memcpy(&zBuf[n], x, sizeof(x))
n += 16;// sizeof(x);
}

#endif
            if (sizeof(DWORD) <= nBuf - n)
            {
                //DWORD pid = GetCurrentProcessId();
                System.Random r = new Random();
                uint i = (uint)r.Next();

                put32bits(zBuf, n, i);//(memcpy(&zBuf[n], pid, sizeof(pid));
                n += 4;// sizeof(pid);
            }
            System.DateTime dt = new System.DateTime();
            if (sizeof(DWORD) <= nBuf - n)
            {
                //DWORD cnt = GetTickCount();
                put32bits(zBuf, n, (u32)dt.Ticks);// memcpy(&zBuf[n], cnt, sizeof(cnt));
                n += 4;// cnt.Length;
            }
            if (sizeof(long) <= nBuf - n)
            {
                long i = dt.Ticks;
                put32bits(zBuf, n, (u32)(i & 0xFFFFFFFF));//memcpy(&zBuf[n], i, sizeof(i));
                put32bits(zBuf, n, (u32)(i >> 32));
                n += sizeof(long);
            }
#endif
            return n;
        }


        /*
        ** Sleep for a little while.  Return the amount of time slept.
        */
        static int winSleep(sqlite3_vfs pVfs, int microsec)
        {
            Thread.Sleep((microsec + 999) / 1000);
            UNUSED_PARAMETER(pVfs);
            return ((microsec + 999) / 1000) * 1000;
        }

        /*
        ** The following variable, if set to a non-zero value, becomes the result
        ** returned from sqlite3OsCurrentTime().  This is used for testing.
        */
#if SQLITE_TEST
    //    static int sqlite3_current_time = 0;
#endif

        /*
** Find the current time (in Universal Coordinated Time).  Write the
** current time and date as a Julian Day number into prNow and
** return 0.  Return 1 if the time and date cannot be found.
*/
        static int winCurrentTime(sqlite3_vfs pVfs, ref double prNow)
        {
            FILETIME ft = new FILETIME();
            /* FILETIME structure is a 64-bit value representing the number of 
            100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). 
            */
            sqlite3_int64 timeW;   /* Whole days */
            sqlite3_int64 timeF;   /* Fractional Days */

            /* Number of 100-nanosecond intervals in a single day */
            const sqlite3_int64 ntuPerDay =
            10000000 * (sqlite3_int64)86400;

            /* Number of 100-nanosecond intervals in half of a day */
            const sqlite3_int64 ntuPerHalfDay =
            10000000 * (sqlite3_int64)43200;

            /* 2^32 - to avoid use of LL and warnings in gcc */
            const sqlite3_int64 max32BitValue =
            (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;

            //#if SQLITE_OS_WINCE
            //SYSTEMTIME time;
            //GetSystemTime(&time);
            ///* if SystemTimeToFileTime() fails, it returns zero. */
            //if (!SystemTimeToFileTime(&time,&ft)){
            //return 1;
            //}
            //#else
            //      GetSystemTimeAsFileTime( ref ft );
            //      ft = System.DateTime.UtcNow.ToFileTime();
            //#endif
            //      UNUSED_PARAMETER( pVfs );
            //      timeW = ( ( (sqlite3_int64)ft.dwHighDateTime ) * max32BitValue ) + (sqlite3_int64)ft.dwLowDateTime;
            timeW = System.DateTime.UtcNow.ToFileTime();
            timeF = timeW % ntuPerDay;          /* fractional days (100-nanoseconds) */
            timeW = timeW / ntuPerDay;          /* whole days */
            timeW = timeW + 2305813;            /* add whole days (from 2305813.5) */
            timeF = timeF + ntuPerHalfDay;      /* add half a day (from 2305813.5) */
            timeW = timeW + (timeF / ntuPerDay);  /* add whole day if half day made one */
            timeF = timeF % ntuPerDay;          /* compute new fractional days */
            prNow = (double)timeW + ((double)timeF / (double)ntuPerDay);
#if SQLITE_TEST
      if ( ( sqlite3_current_time.iValue ) != 0 )
      {
        prNow = ( (double)sqlite3_current_time.iValue + (double)43200 ) / (double)86400 + (double)2440587;
      }
#endif
            return 0;
        }


        /*
        ** The idea is that this function works like a combination of
        ** GetLastError() and FormatMessage() on windows (or errno and
        ** strerror_r() on unix). After an error is returned by an OS
        ** function, SQLite calls this function with zBuf pointing to
        ** a buffer of nBuf bytes. The OS layer should populate the
        ** buffer with a nul-terminated UTF-8 encoded error message
        ** describing the last IO error to have occurred within the calling
        ** thread.
        **
        ** If the error message is too large for the supplied buffer,
        ** it should be truncated. The return value of xGetLastError
        ** is zero if the error message fits in the buffer, or non-zero
        ** otherwise (if the message was truncated). If non-zero is returned,
        ** then it is not necessary to include the nul-terminator character
        ** in the output buffer.
        **
        ** Not supplying an error message will have no adverse effect
        ** on SQLite. It is fine to have an implementation that never
        ** returns an error message:
        **
        **   int xGetLastError(sqlite3_vfs pVfs, int nBuf, char *zBuf){
        **     Debug.Assert(zBuf[0]=='\0');
        **     return 0;
        **   }
        **
        ** However if an error message is supplied, it will be incorporated
        ** by sqlite into the error message available to the user using
        ** sqlite3_errmsg(), possibly making IO errors easier to debug.
        */
        static int winGetLastError(sqlite3_vfs pVfs, int nBuf, ref string zBuf)
        {
            UNUSED_PARAMETER(pVfs);
            return getLastErrorMsg(nBuf, ref zBuf);
        }

        static sqlite3_vfs winVfs = new sqlite3_vfs(
        1,                              /* iVersion */
        -1, //sqlite3_file.Length,      /* szOsFile */
        MAX_PATH,                       /* mxPathname */
        null,                           /* pNext */
        "win32",                        /* zName */
        0,                              /* pAppData */

        (dxOpen)winOpen,                /* xOpen */
        (dxDelete)winDelete,            /* xDelete */
        (dxAccess)winAccess,            /* xAccess */
        (dxFullPathname)winFullPathname,/* xFullPathname */
        (dxDlOpen)winDlOpen,            /* xDlOpen */
        (dxDlError)winDlError,          /* xDlError */
        (dxDlSym)winDlSym,              /* xDlSym */
        (dxDlClose)winDlClose,          /* xDlClose */
        (dxRandomness)winRandomness,    /* xRandomness */
        (dxSleep)winSleep,              /* xSleep */
        (dxCurrentTime)winCurrentTime,  /* xCurrentTime */
        (dxGetLastError)winGetLastError /* xGetLastError */
        );



        /*
        ** Initialize and deinitialize the operating system interface.
        */
        static int sqlite3_os_init()
        {
            sqlite3_vfs_register(winVfs, 1);
            return SQLITE_OK;
        }
        static int sqlite3_os_end()
        {
            return SQLITE_OK;
        }

#endif // * SQLITE_OS_WIN */
        //
        //          Windows DLL definitions
        //

#if ! SQLITE_SILVERLIGHT
    [DllImport( "kernel32.dll", SetLastError = true )]
    static extern int FormatMessageA( int dwFlags, ref object lpSource,
    int dwMessageId, int dwLanguageId, string lpBuffer,
    int nSize, ref int Arguments );

    [DllImport( "kernel32.dll", SetLastError = true )]
    static extern int FlushFileBuffers( IntPtr hFile );

    [DllImport( "kernel32", SetLastError = true )]
    static extern int GetLastError();

    [DllImport( "kernel32", SetLastError = true )]
    static extern int LockFile(int hFile, int dwFileOffsetLow, int dwFileOffsetHigh, int nNumberOfBytesToLockLow, int nNumberOfBytesToLockHigh);

    [DllImport( "kernel32", SetLastError = true )]
    static extern int LockFileEx(int hFile, int dwFlags, int dwReserved, int nNumberOfBytesToLockLow, int nNumberOfBytesToLockHigh, ref OVERLAPPED lpOverlapped);
    const int LOCKFILE_EXCLUSIVE_LOCK = 0x00000002;

    [DllImport( "kernel32", SetLastError = true )]
    static extern int UnlockFile( IntPtr hFile, int dwFileOffsetLow, int dwFileOffsetHigh, int nNumberOfBytesToUnlockLow, int nNumberOfBytesToUnlockHigh );

#endif


        public struct OVERLAPPED
        {
            public int Internal;
            public int InternalHigh;
            public int Offset;
            public int OffsetHigh;
            public int hEvent;
        }


        const u32 GENERIC_READ = 0x80000000;
        const int GENERIC_WRITE = 0x40000000;
        const int FILE_SHARE_READ = 0x1;
        const int FILE_SHARE_WRITE = 0x2;
        const int CREATE_ALWAYS = 2;
        const int CREATE_NEW = 1;
        const int OPEN_ALWAYS = 4;
        const int OPEN_EXISTING = 3;
        const int TRUNCATE_EXISTING = 5;
        const int FILE_ATTRIBUTE_ARCHIVE = 0x20;
        const int FILE_ATTRIBUTE_READONLY = 0x1;
        const int FILE_ATTRIBUTE_HIDDEN = 0x2;
        const int FILE_ATTRIBUTE_SYSTEM = 0x4;
        const int FILE_ATTRIBUTE_NORMAL = 0x80;
        const int FILE_ATTRIBUTE_TEMPORARY = 0x100;
        const int FILE_FLAG_DELETE_ON_CLOSE = 0x4000000;
        const int FILE_FLAG_NO_BUFFERING = 0x20000000;
        const int FILE_FLAG_OVERLAPPED = 0x40000000;
        const int FILE_FLAG_POSIX_SEMANTICS = 0x1000000;
        const int FILE_FLAG_RANDOM_ACCESS = 0x10000000;
        const int FILE_FLAG_SEQUENTIAL_SCAN = 0x8000000;
        const u32 FILE_FLAG_WRITE_THROUGH = 0x80000000;

        const int INVALID_HANDLE_VALUE = -1;
        const int NO_ERROR = 0;

        const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
        // These are the Win32 error code for file not found or access denied.
        const int ERROR_FILE_NOT_FOUND = 2;
        const int ERROR_ACCESS_DENIED = 5;
    }
}
